/*
** Xin YUAN, 2024, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------

//transpose

template <typename T>
inline Mat2x2<T> Mat_Transpose(const Mat2x2<T>& m) noexcept
{
	return Mat2x2<T>(m.v._11, m.v._12,
			m.v._21, m.v._22);
}
template <typename T>
inline Mat3x2<T> Mat_Transpose(const Mat2x3<T>& m) noexcept
{
	return Mat3x2<T>(m.v._11, m.v._12,
			m.v._21, m.v._22,
			m.v._31, m.v._32);
}
template <typename T>
inline Mat4x2<T> Mat_Transpose(const Mat2x4<T>& m) noexcept
{
	return Mat4x2<T>(m.v._11, m.v._12,
			m.v._21, m.v._22,
			m.v._31, m.v._32,
			m.v._41, m.v._42);
}

template <typename T>
inline Mat2x3<T> Mat_Transpose(const Mat3x2<T>& m) noexcept
{
	return Mat2x3<T>(m.v._11, m.v._12, m.v._13,
			m.v._21, m.v._22, m.v._23);
}
template <typename T>
inline Mat3x3<T> Mat_Transpose(const Mat3x3<T>& m) noexcept
{
	return Mat3x3<T>(m.v._11, m.v._12, m.v._13,
			m.v._21, m.v._22, m.v._23,
			m.v._31, m.v._32, m.v._33);
}
template <typename T>
inline Mat4x3<T> Mat_Transpose(const Mat3x4<T>& m) noexcept
{
	return Mat4x3<T>(m.v._11, m.v._12, m.v._13,
			m.v._21, m.v._22, m.v._23,
			m.v._31, m.v._32, m.v._33,
			m.v._41, m.v._42, m.v._43);
}

template <typename T>
inline Mat2x4<T> Mat_Transpose(const Mat4x2<T>& m) noexcept
{
	return Mat2x4<T>(m.v._11, m.v._12, m.v._13, m.v._14,
			m.v._21, m.v._22, m.v._23, m.v._24);
}
template <typename T>
inline Mat3x4<T> Mat_Transpose(const Mat4x3<T>& m) noexcept
{
	return Mat3x4<T>(m.v._11, m.v._12, m.v._13, m.v._14,
			m.v._21, m.v._22, m.v._23, m.v._24,
			m.v._31, m.v._32, m.v._33, m.v._34);
}
template <typename T>
inline Mat4x4<T> Mat_Transpose(const Mat4x4<T>& m) noexcept
{
	return Mat4x4<T>(m.v._11, m.v._12, m.v._13, m.v._14,
			m.v._21, m.v._22, m.v._23, m.v._24,
			m.v._31, m.v._32, m.v._33, m.v._34,
			m.v._41, m.v._42, m.v._43, m.v._44);
}

//determinant

template <typename T>
inline T Mat_Determinant(const Mat2x2<T>& m) noexcept
{
	return m.v._11 * m.v._22 - m.v._12 * m.v._21;
}
template <typename T>
inline T Mat_Determinant(const Mat3x3<T>& m) noexcept
{
	return m.v._11 * (m.v._22 * m.v._33 - m.v._23 * m.v._32)
	     - m.v._12 * (m.v._21 * m.v._33 - m.v._23 * m.v._31)
	     + m.v._13 * (m.v._21 * m.v._32 - m.v._22 * m.v._31);
}
template <typename T>
inline T Mat_Determinant(const Mat4x4<T>& m) noexcept
{
	T f00 = m.v._33 * m.v._44 - m.v._34 * m.v._43;
	T f01 = m.v._23 * m.v._44 - m.v._24 * m.v._43;
	T f02 = m.v._23 * m.v._34 - m.v._24 * m.v._33;
	T f03 = m.v._13 * m.v._44 - m.v._14 * m.v._43;
	T f04 = m.v._13 * m.v._34 - m.v._14 * m.v._33;
	T f05 = m.v._13 * m.v._24 - m.v._14 * m.v._23;
	Vec4<T> vDetCof(
			  (m.v._22 * f00 - m.v._32 * f01 + m.v._42 * f02),
			- (m.v._12 * f00 - m.v._32 * f03 + m.v._42 * f04),
			  (m.v._12 * f01 - m.v._22 * f03 + m.v._42 * f05),
			- (m.v._12 * f02 - m.v._22 * f04 + m.v._32 * f05)
			);
	return m.v._11 * vDetCof.data[0] + m.v._21 * vDetCof.data[1]
	     + m.v._31 * vDetCof.data[2] + m.v._41 * vDetCof.data[3];
}

//inverse

template <typename T>
inline Mat2x2<T> Mat_Inverse(const Mat2x2<T>& m) noexcept
{
	T fOneOverDeterminant = (T)1 / Mat_Determinant(m);
	return Mat2x2<T>(
			  m.v._22 * fOneOverDeterminant,
			- m.v._21 * fOneOverDeterminant,
			- m.v._12 * fOneOverDeterminant,
			  m.v._11 * fOneOverDeterminant);
}
template <typename T>
inline Mat3x3<T> Mat_Inverse(const Mat3x3<T>& m) noexcept
{
	T fOneOverDeterminant = (T)1 / Mat_Determinant(m);
	Mat3x3<T> ret;
	ret.v._11 =   (m.v._22 * m.v._33 - m.v._23 * m.v._32) * fOneOverDeterminant;
	ret.v._12 = - (m.v._12 * m.v._33 - m.v._13 * m.v._32) * fOneOverDeterminant;
	ret.v._13 =   (m.v._12 * m.v._23 - m.v._13 * m.v._22) * fOneOverDeterminant;
	ret.v._21 = - (m.v._21 * m.v._33 - m.v._23 * m.v._31) * fOneOverDeterminant;
	ret.v._22 =   (m.v._11 * m.v._33 - m.v._13 * m.v._31) * fOneOverDeterminant;
	ret.v._23 = - (m.v._11 * m.v._23 - m.v._13 * m.v._21) * fOneOverDeterminant;
	ret.v._31 =   (m.v._21 * m.v._32 - m.v._22 * m.v._31) * fOneOverDeterminant;
	ret.v._32 = - (m.v._11 * m.v._32 - m.v._12 * m.v._31) * fOneOverDeterminant;
	ret.v._33 =   (m.v._11 * m.v._22 - m.v._12 * m.v._21) * fOneOverDeterminant;
	return ret;
}
template <typename T>
inline Mat4x4<T> Mat_Inverse(const Mat4x4<T>& m) noexcept
{
	T coef00 = m.v._33 * m.v._44 - m.v._34 * m.v._43;
	T coef02 = m.v._32 * m.v._44 - m.v._34 * m.v._42;
	T coef03 = m.v._32 * m.v._43 - m.v._33 * m.v._42;

	T coef04 = m.v._23 * m.v._44 - m.v._24 * m.v._43;
	T coef06 = m.v._22 * m.v._44 - m.v._24 * m.v._42;
	T coef07 = m.v._22 * m.v._43 - m.v._23 * m.v._42;

	T coef08 = m.v._23 * m.v._34 - m.v._24 * m.v._33;
	T coef10 = m.v._22 * m.v._34 - m.v._24 * m.v._32;
	T coef11 = m.v._22 * m.v._33 - m.v._23 * m.v._32;

	T coef12 = m.v._13 * m.v._44 - m.v._14 * m.v._43;
	T coef14 = m.v._12 * m.v._44 - m.v._14 * m.v._42;
	T coef15 = m.v._12 * m.v._43 - m.v._13 * m.v._42;

	T coef16 = m.v._13 * m.v._34 - m.v._14 * m.v._33;
	T coef18 = m.v._12 * m.v._34 - m.v._14 * m.v._32;
	T coef19 = m.v._12 * m.v._33 - m.v._13 * m.v._32;

	T coef20 = m.v._13 * m.v._24 - m.v._14 * m.v._23;
	T coef22 = m.v._12 * m.v._24 - m.v._14 * m.v._22;
	T coef23 = m.v._12 * m.v._23 - m.v._13 * m.v._22;

	Vec4<T> vFac0(coef00, coef00, coef02, coef03);
	Vec4<T> vFac1(coef04, coef04, coef06, coef07);
	Vec4<T> vFac2(coef08, coef08, coef10, coef11);
	Vec4<T> vFac3(coef12, coef12, coef14, coef15);
	Vec4<T> vFac4(coef16, coef16, coef18, coef19);
	Vec4<T> vFac5(coef20, coef20, coef22, coef23);

	Vec4<T> vec0(m.v._12, m.v._11, m.v._11, m.v._11);
	Vec4<T> vec1(m.v._22, m.v._21, m.v._21, m.v._21);
	Vec4<T> vec2(m.v._32, m.v._31, m.v._31, m.v._31);
	Vec4<T> vec3(m.v._42, m.v._41, m.v._41, m.v._41);

	Vec4<T> inv0(vec1 * vFac0 - vec2 * vFac1 + vec3 * vFac2);
	Vec4<T> inv1(vec0 * vFac0 - vec2 * vFac3 + vec3 * vFac4);
	Vec4<T> inv2(vec0 * vFac1 - vec1 * vFac3 + vec3 * vFac5);
	Vec4<T> inv3(vec0 * vFac2 - vec1 * vFac4 + vec2 * vFac5);

	Vec4<T> vSignA(+1, -1, +1, -1);
	Vec4<T> vSignB(-1, +1, -1, +1);

	Mat4x4<T> mInverse(inv0 * vSignA, inv1 * vSignB, inv2 * vSignA, inv3 * vSignB);

	Vec4<T> vRow0(mInverse.v._11, mInverse.v._12, mInverse.v._13, mInverse.v._14);

	Vec4<T> vDot0(m.data[0] * vRow0);

	T fDot1 = (vDot0.coord.x + vDot0.coord.y) + (vDot0.coord.z + vDot0.coord.w);
	T fOneOverDeterminant = (T)1 / (fDot1);

	return mInverse * fOneOverDeterminant;
}

//------------------------------------------------------------------------------

//multiplication

template <typename T>
inline Vec2<T> operator*(const Vec2<T>& v, const Mat2x2<T>& m) noexcept
{
	return Vec2<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21,
			v.coord.x * m.v._12 + v.coord.y * m.v._22);
}
template <typename T>
inline Mat2x2<T> operator*(const Mat2x2<T>& m1, const Mat2x2<T>& m2) noexcept
{
	return Mat2x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22);
}
template <typename T>
inline Mat3x2<T> operator*(const Mat2x2<T>& m1, const Mat3x2<T>& m2) noexcept
{
	return Mat3x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23);
}
template <typename T>
inline Mat4x2<T> operator*(const Mat2x2<T>& m1, const Mat4x2<T>& m2) noexcept
{
	return Mat4x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24);
}

template <typename T>
inline Vec2<T> operator*(const Vec3<T>& v, const Mat2x3<T>& m) noexcept
{
	return Vec2<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32);
}
template <typename T>
inline Mat2x3<T> operator*(const Mat2x3<T>& m1, const Mat2x2<T>& m2) noexcept
{
	return Mat2x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22);
}
template <typename T>
inline Mat3x3<T> operator*(const Mat2x3<T>& m1, const Mat3x2<T>& m2) noexcept
{
	return Mat3x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23);
}
template <typename T>
inline Mat4x3<T> operator*(const Mat2x3<T>& m1, const Mat4x2<T>& m2) noexcept
{
	return Mat4x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24,
			m1.v._31 * m2.v._14 + m1.v._32 * m2.v._24);
}

template <typename T>
inline Vec2<T> operator*(const Vec4<T>& v, const Mat2x4<T>& m) noexcept
{
	return Vec2<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31 + v.coord.w * m.v._41,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32 + v.coord.w * m.v._42);
}
template <typename T>
inline Mat2x4<T> operator*(const Mat2x4<T>& m1, const Mat2x2<T>& m2) noexcept
{
	return Mat2x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22);
}
template <typename T>
inline Mat3x4<T> operator*(const Mat2x4<T>& m1, const Mat3x2<T>& m2) noexcept
{
	return Mat3x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23,
			m1.v._41 * m2.v._13 + m1.v._42 * m2.v._23);
}
template <typename T>
inline Mat4x4<T> operator*(const Mat2x4<T>& m1, const Mat4x2<T>& m2) noexcept
{
	return Mat4x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23,
			m1.v._41 * m2.v._13 + m1.v._42 * m2.v._23,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24,
			m1.v._31 * m2.v._14 + m1.v._32 * m2.v._24,
			m1.v._41 * m2.v._14 + m1.v._42 * m2.v._24);
}

template <typename T>
inline Vec3<T> operator*(const Vec2<T>& v, const Mat3x2<T>& m) noexcept
{
	return Vec3<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21,
			v.coord.x * m.v._12 + v.coord.y * m.v._22,
			v.coord.x * m.v._13 + v.coord.y * m.v._23);
}
template <typename T>
inline Mat2x2<T> operator*(const Mat3x2<T>& m1, const Mat2x3<T>& m2) noexcept
{
	return Mat2x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32);
}
template <typename T>
inline Mat3x2<T> operator*(const Mat3x2<T>& m1, const Mat3x3<T>& m2) noexcept
{
	return Mat3x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33);
}
template <typename T>
inline Mat4x2<T> operator*(const Mat3x2<T>& m1, const Mat4x3<T>& m2) noexcept
{
	return Mat4x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24 + m1.v._13 * m2.v._34,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24 + m1.v._23 * m2.v._34);
}

template <typename T>
inline Vec3<T> operator*(const Vec3<T>& v, const Mat3x3<T>& m) noexcept
{
	return Vec3<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32,
			v.coord.x * m.v._13 + v.coord.y * m.v._23 + v.coord.z * m.v._33);
}
template <typename T>
inline Mat2x3<T> operator*(const Mat3x3<T>& m1, const Mat2x3<T>& m2) noexcept
{
	return Mat2x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32);
}
template <typename T>
inline Mat3x3<T> operator*(const Mat3x3<T>& m1, const Mat3x3<T>& m2) noexcept
{
	return Mat3x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33);
}
template <typename T>
inline Mat4x3<T> operator*(const Mat3x3<T>& m1, const Mat4x3<T>& m2) noexcept
{
	return Mat4x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24 + m1.v._13 * m2.v._34,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24 + m1.v._23 * m2.v._34,
			m1.v._31 * m2.v._14 + m1.v._32 * m2.v._24 + m1.v._33 * m2.v._34);
}

template <typename T>
inline Vec3<T> operator*(const Vec4<T>& v, const Mat3x4<T>& m) noexcept
{
	return Vec3<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31 + v.coord.w * m.v._41,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32 + v.coord.w * m.v._42,
			v.coord.x * m.v._13 + v.coord.y * m.v._23 + v.coord.z * m.v._33 + v.coord.w * m.v._43);
}
template <typename T>
inline Mat2x4<T> operator*(const Mat3x4<T>& m1, const Mat2x3<T>& m2) noexcept
{
	return Mat2x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21 + m1.v._43 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22 + m1.v._43 * m2.v._32);
}
template <typename T>
inline Mat3x4<T> operator*(const Mat3x4<T>& m1, const Mat3x3<T>& m2) noexcept
{
	return Mat3x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21 + m1.v._43 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22 + m1.v._43 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33,
			m1.v._41 * m2.v._13 + m1.v._42 * m2.v._23 + m1.v._43 * m2.v._33);
}
template <typename T>
inline Mat4x4<T> operator*(const Mat3x4<T>& m1, const Mat4x3<T>& m2) noexcept
{
	return Mat4x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21 + m1.v._43 * m2.v._31,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22 + m1.v._43 * m2.v._32,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33,
			m1.v._41 * m2.v._13 + m1.v._42 * m2.v._23 + m1.v._43 * m2.v._33,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24 + m1.v._13 * m2.v._34,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24 + m1.v._23 * m2.v._34,
			m1.v._31 * m2.v._14 + m1.v._32 * m2.v._24 + m1.v._33 * m2.v._34,
			m1.v._41 * m2.v._14 + m1.v._42 * m2.v._24 + m1.v._43 * m2.v._34);
}

template <typename T>
inline Vec4<T> operator*(const Vec2<T>& v, const Mat4x2<T>& m) noexcept
{
	return Vec4<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21,
			v.coord.x * m.v._12 + v.coord.y * m.v._22,
			v.coord.x * m.v._13 + v.coord.y * m.v._23,
			v.coord.x * m.v._14 + v.coord.y * m.v._24);
}
template <typename T>
inline Mat2x2<T> operator*(const Mat4x2<T>& m1, const Mat2x4<T>& m2) noexcept
{
	return Mat2x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42);
}
template <typename T>
inline Mat3x2<T> operator*(const Mat4x2<T>& m1, const Mat3x4<T>& m2) noexcept
{
	return Mat3x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33 + m1.v._14 * m2.v._43,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33 + m1.v._24 * m2.v._43);
}
template <typename T>
inline Mat4x2<T> operator*(const Mat4x2<T>& m1, const Mat4x4<T>& m2) noexcept
{
	return Mat4x2<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33 + m1.v._14 * m2.v._43,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33 + m1.v._24 * m2.v._43,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24 + m1.v._13 * m2.v._34 + m1.v._14 * m2.v._44,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24 + m1.v._23 * m2.v._34 + m1.v._24 * m2.v._44);
}

template <typename T>
inline Vec4<T> operator*(const Vec3<T>& v, const Mat4x3<T>& m) noexcept
{
	return Vec4<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32,
			v.coord.x * m.v._13 + v.coord.y * m.v._23 + v.coord.z * m.v._33,
			v.coord.x * m.v._14 + v.coord.y * m.v._24 + v.coord.z * m.v._34);
}
template <typename T>
inline Mat2x3<T> operator*(const Mat4x3<T>& m1, const Mat2x4<T>& m2) noexcept
{
	return Mat2x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31 + m1.v._34 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32 + m1.v._34 * m2.v._42);
}
template <typename T>
inline Mat3x3<T> operator*(const Mat4x3<T>& m1, const Mat3x4<T>& m2) noexcept
{
	return Mat3x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31 + m1.v._34 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32 + m1.v._34 * m2.v._42,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33 + m1.v._14 * m2.v._43,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33 + m1.v._24 * m2.v._43,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33 + m1.v._34 * m2.v._43);
}
template <typename T>
inline Mat4x3<T> operator*(const Mat4x3<T>& m1, const Mat4x4<T>& m2) noexcept
{
	return Mat4x3<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31 + m1.v._34 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32 + m1.v._34 * m2.v._42,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33 + m1.v._14 * m2.v._43,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33 + m1.v._24 * m2.v._43,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33 + m1.v._34 * m2.v._43,
			m1.v._11 * m2.v._14 + m1.v._12 * m2.v._24 + m1.v._13 * m2.v._34 + m1.v._14 * m2.v._44,
			m1.v._21 * m2.v._14 + m1.v._22 * m2.v._24 + m1.v._23 * m2.v._34 + m1.v._24 * m2.v._44,
			m1.v._31 * m2.v._14 + m1.v._32 * m2.v._24 + m1.v._33 * m2.v._34 + m1.v._34 * m2.v._44);
}

template <typename T>
inline Vec4<T> operator*(const Vec4<T>& v, const Mat4x4<T>& m) noexcept
{
	return Vec4<T>(
			v.coord.x * m.v._11 + v.coord.y * m.v._21 + v.coord.z * m.v._31 + v.coord.w * m.v._41,
			v.coord.x * m.v._12 + v.coord.y * m.v._22 + v.coord.z * m.v._32 + v.coord.w * m.v._42,
			v.coord.x * m.v._13 + v.coord.y * m.v._23 + v.coord.z * m.v._33 + v.coord.w * m.v._43,
			v.coord.x * m.v._14 + v.coord.y * m.v._24 + v.coord.z * m.v._34 + v.coord.w * m.v._44);
}
template <typename T>
inline Mat2x4<T> operator*(const Mat4x4<T>& m1, const Mat2x4<T>& m2) noexcept
{
	return Mat2x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31 + m1.v._34 * m2.v._41,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21 + m1.v._43 * m2.v._31 + m1.v._44 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32 + m1.v._34 * m2.v._42,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22 + m1.v._43 * m2.v._32 + m1.v._44 * m2.v._42);
}
template <typename T>
inline Mat3x4<T> operator*(const Mat4x4<T>& m1, const Mat3x4<T>& m2) noexcept
{
	return Mat3x4<T>(
			m1.v._11 * m2.v._11 + m1.v._12 * m2.v._21 + m1.v._13 * m2.v._31 + m1.v._14 * m2.v._41,
			m1.v._21 * m2.v._11 + m1.v._22 * m2.v._21 + m1.v._23 * m2.v._31 + m1.v._24 * m2.v._41,
			m1.v._31 * m2.v._11 + m1.v._32 * m2.v._21 + m1.v._33 * m2.v._31 + m1.v._34 * m2.v._41,
			m1.v._41 * m2.v._11 + m1.v._42 * m2.v._21 + m1.v._43 * m2.v._31 + m1.v._44 * m2.v._41,
			m1.v._11 * m2.v._12 + m1.v._12 * m2.v._22 + m1.v._13 * m2.v._32 + m1.v._14 * m2.v._42,
			m1.v._21 * m2.v._12 + m1.v._22 * m2.v._22 + m1.v._23 * m2.v._32 + m1.v._24 * m2.v._42,
			m1.v._31 * m2.v._12 + m1.v._32 * m2.v._22 + m1.v._33 * m2.v._32 + m1.v._34 * m2.v._42,
			m1.v._41 * m2.v._12 + m1.v._42 * m2.v._22 + m1.v._43 * m2.v._32 + m1.v._44 * m2.v._42,
			m1.v._11 * m2.v._13 + m1.v._12 * m2.v._23 + m1.v._13 * m2.v._33 + m1.v._14 * m2.v._43,
			m1.v._21 * m2.v._13 + m1.v._22 * m2.v._23 + m1.v._23 * m2.v._33 + m1.v._24 * m2.v._43,
			m1.v._31 * m2.v._13 + m1.v._32 * m2.v._23 + m1.v._33 * m2.v._33 + m1.v._34 * m2.v._43,
			m1.v._41 * m2.v._13 + m1.v._42 * m2.v._23 + m1.v._43 * m2.v._33 + m1.v._44 * m2.v._43);
}
template <typename T>
inline Mat4x4<T> operator*(const Mat4x4<T>& m1, const Mat4x4<T>& m2) noexcept
{
	Vec4<T> const vSrcA0 = m1.data[0];
	Vec4<T> const vSrcA1 = m1.data[1];
	Vec4<T> const vSrcA2 = m1.data[2];
	Vec4<T> const vSrcA3 = m1.data[3];

	Vec4<T> const vSrcB0 = m2.data[0];
	Vec4<T> const vSrcB1 = m2.data[1];
	Vec4<T> const vSrcB2 = m2.data[2];
	Vec4<T> const vSrcB3 = m2.data[3];

	return Mat4x4<T>(
		vSrcA0 * vSrcB0.data[0] + vSrcA1 * vSrcB0.data[1] + vSrcA2 * vSrcB0.data[2] + vSrcA3 * vSrcB0.data[3],
		vSrcA0 * vSrcB1.data[0] + vSrcA1 * vSrcB1.data[1] + vSrcA2 * vSrcB1.data[2] + vSrcA3 * vSrcB1.data[3],
		vSrcA0 * vSrcB2.data[0] + vSrcA1 * vSrcB2.data[1] + vSrcA2 * vSrcB2.data[2] + vSrcA3 * vSrcB2.data[3],
		vSrcA0 * vSrcB3.data[0] + vSrcA1 * vSrcB3.data[1] + vSrcA2 * vSrcB3.data[2] + vSrcA3 * vSrcB3.data[3]);
}

////////////////////////////////////////////////////////////////////////////////
